
/**
 * This class represents an active effect, usually associated with a card.
 * @author Sean Wheeler
 *
 */
public class EffectActive{
	public static Class<?>[] effectList = getEffectList();
	
	enum ActiveType{Attack, Chain, DamageEgo, HealEgo, Trap, Counter, EgoBuff, ChargeBuff, ChargeDestroyer, EgoCostModifier, BottomStrike};
	/* 
	* Attack - Deals damage.
	* Chain - Deals damage to every block in the tower.
	* DamageEgo - Reduces the opponent's ego.
	* HealEgo - Restore the player's ego.
	* Trap - Reduces the effect of something (e.g. "Take 50% damage")
	* Counter - Prevents something from happening (e.g. "Nullify opponent's card")
	* EgoBuff - Increases player's Ego Regen
	* ChargeBuff - Adds an extra charge (of a suit specified by the card, as a player decision, or randomly) to the player.
	* ChargeDestroyer - Removes a charge (of a suit specified by the card, as a player decision, or randomly) from the opponent.
	* EgoCostModifier - Alters the ego cost of all cards played for a duration. (100% = normal ego costs)
	* BottomStrike - Deals damage to the bottom of the tower.
	*
	* Effects still needed (from most important to least):
	* LoseHealth - Lose X health from your own tower, ignoring damage-altering effects
	* BuildBuff - Your next block (of a particular suit or any) is X% taller. (Spyglass)
	* HealBlock - Restores health to a particular block (Mason)
	* ExtraSpell - Allows the player to play an additional spell. (Poet)
	* Trickster - Has the same effect as the card the opponent plays this turn.
	*/
	
	public Command type;
	public int magnitude;
	public String sub;
	public Player user, opponent;
	
	/**
	 * Create an active effect with the following params
	 * @param type The type of effect
	 * @param magnitude The magnitude of its effect
	 */
	
	/**
	 * Create an active effect with the following properties
	 * @param type The type of Effect you want
	 * @param magnitude The magnitude of the effect
	 * @param opponent 
	 * @param sub The subtype of the Effect, specifications really
	 */
	public EffectActive(String type, int magnitude, Player user, Player opponent, String sub)
	{
		this.type = this.createEffect(type);
		this.magnitude = magnitude;
		this.user = user;
		this.opponent=opponent;
		this.sub=sub;
	}
	
	public EffectActive(){
		this("AttackCommand",0,null,null, null);
	}
	
	public EffectActive(String type, int magnitude, Player user) {
		this(type,magnitude,user,null,null);
	}

	public void setopponent(Player opponent){
		this.opponent = opponent;
	}
	
	public void checkReflection(int damage){
		for(int i=0; i<user.getBuffs().size(); i++){
			if(user.getBuffs().get(i) instanceof Herring)
				((Herring) user.getBuffs().get(i)).reflect(user, damage);
		}
	}
	
	public void removeLookingGlass(){
		for(int i=0; i<user.getBuffs().size(); i++){
			if(user.getBuffs().get(i) instanceof LookingGlass || user.getBuffs().get(i) instanceof BuildReduce || user.getBuffs().get(i) instanceof BuildBuff)
				user.getBuffs().remove(i);
		}		
	}
	
	public void removeDamageReduction(){
		for(int i=0; i<user.getBuffs().size(); i++){
			if(user.getBuffs().get(i) instanceof NullifyDamage)
				user.getBuffs().remove(i);
		}			
	}
	
	public void execute(){
		type.execute();
	}
	public class AttackCommand extends Command{
		public void execute() {
			if(sub.equals("Children")){
				Block blockopponent= opponent.getTower().getTopBlock();
				int damage = magnitude * (user.getTower().getHeight()/5);
				blockopponent.takeDamage(damage);
				checkReflection(damage);
				removeDamageReduction();
			}
			else{
				for(int i=opponent.getTower().getNumBlocks()-1; i >= 0; i--){
					Block blockopponent= opponent.getTower().getBlock(i);
					if(blockopponent.getHealth() < magnitude){
						magnitude -= blockopponent.getHealth();
						blockopponent.setHealth(0);
					}
					else{
						blockopponent.takeDamage(magnitude);
						checkReflection(magnitude);
						removeDamageReduction();
						return;
					}
				}
			}
		}
		
	}
	
	public class SelfAttackCommand extends Command{
		public void execute(){
			for(int i=user.getTower().getNumBlocks()-1; i >= 0; i--){
				Block blockuser= user.getTower().getBlock(i);
				if(blockuser.getHealth() < magnitude){
					magnitude -= blockuser.getHealth();
					blockuser.setHealth(0);
				}
				else{
					blockuser.takeDamage(magnitude);
					return;
				}
			}			
		}
	}
	
	public class ChainCommand extends Command{

		@Override
		public void execute() {
			Tower toweropponent=opponent.getTower();
			int towerHeight= toweropponent.getNumBlocks();
			for(int i=0;i<towerHeight;i++){
				Block currentBlock=toweropponent.getBlock(i);
				currentBlock.takeDamage(magnitude);
				checkReflection(magnitude);
				removeDamageReduction();
			}
			
		}
		
	}
	
	public class HealCommand extends Command{
		public void execute(){
			if(sub.equals("Morality")){
				for(int i=0; i< user.getTower().getNumBlocks(); i++){
					user.getTower().getBlock(i).takeDamage((int)(user.getTower().getBlock(i).getHealth()*(-magnitude/100.0)));
				}
			}
			else{
				user.getTower().getTopBlock().takeDamage(-magnitude);
			}
		}
	}
	
	public class HealEgoCommand extends Command{

		@Override
		public void execute() {
			int newEgo= user.getCurrentEgo()+magnitude;
			if(newEgo>200){
				newEgo=200;
			}
			user.setCurrentEgo(newEgo);
			
		}
		
	}
	
	public class DamageEgoCommand extends Command{
	
		@Override
		public void execute() {
			int newEgo= opponent.getCurrentEgo()-magnitude;
			if(newEgo<0){
				newEgo=0;
			}
			opponent.setCurrentEgo(newEgo);
			
		}
			
	}
	
	public class EgoRegenDebuffCommand extends Command{
		public void execute(){
			opponent.setEgoRegen(opponent.getEgoRegen()-magnitude);
		}
	}
	
	public class EgoRegenCommand extends Command{
	
		@Override
		public void execute() {
			user.setEgoRegen(user.getEgoRegen() + magnitude);
			
		}
		
	}
	
	public class ChargeGainCommand extends Command{
	
		@Override
		public void execute() {
			ChargeWheel chrgwheel= user.getCharges();
			chrgwheel.gainRandomCharge();
			
		}
		
	}
	
	public class DestroyChargeCommand extends Command{
	
		@Override
		public void execute() {
			ChargeWheel chrgwheel= opponent.getCharges();
			chrgwheel.destroyRandomCharge();
			
		}
		
	}
	
	public class BottomStrikeCommand extends Command{
	
		@Override
		public void execute() {
			Block target= opponent.getTower().getBottomBlock();
			target.takeDamage(magnitude);
			
		}
		
	}
	
	public class EgoCostDebuffCommand extends Command{
	
		@Override
		public void execute() {
			int duration = 0;
			try{
				duration = Integer.parseInt(sub);
			}
			catch(Exception e){duration = 0;}
			opponent.egoCostRate += magnitude/100.0;
			opponent.buffList.add(new EgoCostDebuff(magnitude, duration));
			
		}
		
	}
	
	public class BuildReduceCommand extends Command{
	
		@Override
		public void execute() {
			int duration = 0;
			try{
				duration = Integer.parseInt(sub);
			}
			catch(Exception e){duration = 0;}
			opponent.buffList.add(new BuildReduce(magnitude, duration));
			
		}
		
	}
	
	public class HerringCommand extends Command{
	
		@Override
		public void execute() {
			int duration = 0;
			try{
				duration = Integer.parseInt(sub);
			}
			catch(Exception e){duration = 0;}
			opponent.buffList.add(new Herring(magnitude, duration));
			
		}
			
		
	}
	
	public class NullifyDamageCommand extends Command{
		
		@Override
		public void execute() {
			int duration = 0;
			try{
				duration = Integer.parseInt(sub);
			}
			catch(Exception e){duration = 0;}
			opponent.buffList.add(new NullifyDamage(magnitude, duration));
			
		}
			
		
	}
	
	public class LookingGlassCommand extends Command{
		
		@Override
		public void execute() {
			int duration = 0;
			try{
					duration = Integer.parseInt(sub);
				}
			catch(Exception e){duration = 0;}
			opponent.buffList.add(new LookingGlass(magnitude, duration));
		}
		
	}
	
	public class BuildBuffCommand extends Command{
		
		@Override
		public void execute() {
			int duration = 0;
			try{
					duration = Integer.parseInt(sub);
			}
			catch(Exception e){duration = 0;}
			user.buffList.add(new BuildBuff(magnitude, duration));
			
		}
		
	}
	
	public class NullifyCardCommand extends Command{
		
		@Override
		public void execute() {
			int duration = 0;
			try{
					duration = Integer.parseInt(sub);
				}
			catch(Exception e){duration = 0;}
			opponent.buffList.add(new NullifyCard(magnitude, duration));
			
		}
		
	}
	
	public class BuildLogicBlockCommand extends Command{

		@Override
		public void execute() {
			if (user.getCharges().getCharge(ChargeWheel.chargeType.LOGIC) > 1)
			{
				Tower userTower= user.getTower();
				user.getCharges().spendCharge(ChargeWheel.chargeType.LOGIC);
				userTower.addBlock(new Block(Block.blockType.Logic));
				userTower.getTopBlock().setHeight(magnitude);
				removeLookingGlass();
			}
			
		}
		
	}
	
	public class BuildEthicsBlockCommand extends Command{

		@Override
		public void execute() {
			if (user.getCharges().getCharge(ChargeWheel.chargeType.ETHICS) > 1)
			{
				Tower userTower= user.getTower();
				user.getCharges().spendCharge(ChargeWheel.chargeType.ETHICS);
				userTower.addBlock(new Block(Block.blockType.Ethics));
				userTower.getTopBlock().setHeight(magnitude);
				removeLookingGlass();
			}
			
		}
		
	}

	public class BuildPassionBlockCommand extends Command{

		@Override
		public void execute() {
			if (user.getCharges().getCharge(ChargeWheel.chargeType.PASSION) > 1)
			{
				Tower userTower= user.getTower();
				user.getCharges().spendCharge(ChargeWheel.chargeType.PASSION);
				userTower.addBlock(new Block(Block.blockType.Passion));
				userTower.getTopBlock().setHeight(magnitude);
				removeLookingGlass();
			}
			
		}
	
	}

	public class BuildDeceptionBlockCommand extends Command{

		@Override
		public void execute() {
			if (user.getCharges().getCharge(ChargeWheel.chargeType.DECEPTION) > 1)
			{
				Tower userTower= user.getTower();
				user.getCharges().spendCharge(ChargeWheel.chargeType.DECEPTION);
				userTower.addBlock(new Block(Block.blockType.Deception));
				userTower.getTopBlock().setHeight(magnitude);
				removeLookingGlass();
			}
			else
			{
				
			}
			
		}
	
	}

	public Command createEffect(String string) {
		Command effect = null;
		System.out.println(string);
		//System.out.println(effectList.length);
		try {
			/*for(int i=0; i<effectList.length; i++){
				//System.out.println(effectList[i].getName());
				if(effectList[i].getName().equals("EffectActive$"+string)){
					//effect = (Command)Class.forName("EffectActive$"+string).newInstance();
					effect = (Command)effectList[i].newInstance();
					System.out.println("Made new effect");
					return effect;
				}
			}*/
			if(string.equals("AttackCommand"))return new AttackCommand();
			if(string.equals("SelfAttackCommand"))return new SelfAttackCommand();
			if(string.equals("ChainCommand"))return new ChainCommand();
			if(string.equals("HealCommand"))return new HealCommand();
			if(string.equals("HealEgoCommand"))return new HealEgoCommand();
			if(string.equals("DamageEgoCommand"))return new DamageEgoCommand();
			if(string.equals("EgoRegenCommand"))return new EgoRegenCommand();
			if(string.equals("ChargeGainCommand"))return new ChargeGainCommand();
			if(string.equals("DestroyChargeCommand"))return new DestroyChargeCommand();
			if(string.equals("BottomStrikeCommand"))return new BottomStrikeCommand();
			if(string.equals("EgoCostDebuffCommand"))return new EgoCostDebuffCommand();
			if(string.equals("BuildReduceCommand"))return new BuildReduceCommand();
			if(string.equals("HerringCommand"))return new HerringCommand();
			if(string.equals("LookingGlassCommand"))return new LookingGlassCommand();
			if(string.equals("BuildBuffCommand"))return new BuildBuffCommand();
			if(string.equals("NullifyDamageCommand"))return new NullifyDamageCommand();
			if(string.equals("NullifyCardCommand"))return new NullifyCardCommand();
			if(string.equals("BuildLogicBlockCommand"))return new BuildLogicBlockCommand();
			if(string.equals("BuildPassionBlockCommand"))return new BuildPassionBlockCommand();
			if(string.equals("BuildDeceptionBlockCommand"))return new BuildDeceptionBlockCommand();
			if(string.equals("BuildEthicsBlockCommand"))return new BuildEthicsBlockCommand();
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
			return new AttackCommand();
			//System.out.println(string + " not found.");
		}
		
		return new AttackCommand(); //returns a default  command if no match is found
	}
	
	public static Class<?>[] getEffectList(){
		try{
		return Class.forName("EffectActive").getClasses();
		}
		catch(Exception e){e.printStackTrace();System.out.print("effect list failure");}
		return null;
	}
}
